﻿using System;
using System.Collections.Generic;
using System.Diagnostics;

namespace KamLib
{
    public static class CollectionHelper
    {


        #region Dictionary

        /// <summary>
        /// Возвращает Dictionary со списком свойств объекта заданного типа.
        /// Предварительно преобразует с помощью convert
        /// </summary>
        [DebuggerStepThrough]
        public static TValue Try<TKey, TValue>(this Dictionary<TKey, TValue> dic, TKey key)
        {
            return dic != null && dic.ContainsKey(key) ? dic[key] : default(TValue);
        }

        [DebuggerStepThrough]
        public static TValue Try<TKey, TValue>(this IDictionary<TKey, TValue> dic, TKey key)
        {
            return dic != null && dic.ContainsKey(key) ? dic[key] : default(TValue);
        }

        [DebuggerStepThrough]
        public static TResult Try<TKey, TValue, TResult>(this Dictionary<TKey, TValue> dic, TKey key)
            where TValue : class
        {
            object value = dic != null && dic.ContainsKey(key) ? dic[key] : null;
            return (value != null && value is TResult) ? (TResult)value : default(TResult);
        }

        [DebuggerStepThrough]
        public static TResult Try<TKey, TValue, TResult>(this IDictionary<TKey, TValue> dic, TKey key)
            where TValue : class
        {
            object value = dic != null && dic.ContainsKey(key) ? dic[key] : null;
            return (value != null && value is TResult) ? (TResult)value : default(TResult);
        }

        [DebuggerStepThrough]
        public static Dictionary<TKey, TValue> AddRange<TKey, TValue>(this Dictionary<TKey, TValue> self, IDictionary<TKey, TValue> src, bool replace)
        {
            if (src == null) return self;
            foreach (var p in src)
            {
                if (!self.ContainsKey(p.Key))
                    self.Add(p.Key, p.Value);
                else if (replace)
                    self[p.Key] = p.Value;
            }

            return self;
        }

        #endregion


        #region List

        [DebuggerStepThrough]
        public static TItem Find<TItem>(this List<TItem> self, Func<TItem, bool> match)
        {
            if (self == null || match == null) return default(TItem);
            foreach (var item in self)
                if (match(item)) return item;
            return default(TItem);
        }

        [DebuggerStepThrough]
        public static int IndexOf<TItem>(this List<TItem> list, Func<TItem, bool> match)
        {
            if (list == null || match == null) return -1;
            var len = list.Count;
            for (int i = 0; i < len; ++i)
                if (match(list[i])) return i;
            return -1;
        }

        [DebuggerStepThrough]
        public static TItem Register<TItem>(this List<TItem> self, TItem item)
        {
            if (self == null) return default(TItem);
            if (!self.Contains(item))
                self.Add(item);
            return item;
        }
        [DebuggerStepThrough]
        public static void Register<TItem>(this List<TItem> self, IEnumerable<TItem> items)
        {
            if (self == null) return;
            foreach (var item in items)
            {
                if (!self.Contains(item)) self.Add(item);
            }
        }

        /// <summary>
        /// добавляет уникальный элемент в список
        /// </summary>
        /// <param name="item"></param>
        /// <param name="match">поиск существующего элемента</param>
        /// <param name="self"></param>
        /// <returns>возвращает новый или уже существующий элемент</returns>
        [DebuggerStepThrough]
        public static TItem Register<TItem>(this List<TItem> self, TItem item, Func<TItem, bool> match) where TItem : class
        {
            if (self == null) return default(TItem);
            var itm = self.Find(match);
            if (itm != null) return itm;
            self.Add(item);
            return item;
        }

        #endregion

    }
}